package cn.com.yusys.yusp.admin.config;

import cn.com.yusys.yusp.admin.log.BusinessLogProcessor;
import cn.com.yusys.yusp.admin.log.common.AbstractLogProcessor;
import cn.com.yusys.yusp.commons.util.BeanUtil;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Objects;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 异步日志配置.
 * <p>
 * 开启线程池,用于日志记录;
 * 
 * @author: lupan
 * @since 1.0.0
 */
@Configuration
@EnableConfigurationProperties(AsyncLogProperties.class)
public class AsyncLogAutoConfiguration implements DisposableBean {
    
    private static final Logger logger= LoggerFactory.getLogger(AsyncLogAutoConfiguration.class);
    
    private final AsyncLogProperties asyncLogProperties;
    
    private ThreadPoolExecutor threadPoolExecutor;
    public AsyncLogAutoConfiguration(AsyncLogProperties asyncLogProperties) {
        this.asyncLogProperties = asyncLogProperties;
    }

    @Bean
    @ConditionalOnMissingBean(name = "asyncLogThreadPoolExecutor")
    public ThreadPoolExecutor asyncLogThreadPoolExecutor() {
        BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(asyncLogProperties.getQueueSize());
        threadPoolExecutor =  new ThreadPoolExecutor(asyncLogProperties.getCorePoolSize(), asyncLogProperties.getMaxPoolSize(), 5,
                TimeUnit.SECONDS, workQueue);
        return threadPoolExecutor;
    }
    
    public AbstractLogProcessor defaultAsyncLogProcessor() {
        return new BusinessLogProcessor();
    }

    @Bean
    public AbstractLogProcessor dispatchLog() {
        
        AbstractLogProcessor logProcessor = BeanUtil.newInstance(asyncLogProperties.getLogProcessor());
        
        if (Objects.nonNull(logProcessor)) {
            logger.debug("采用日志处理类:{}", asyncLogProperties.getLogProcessor());
            return logProcessor;
        } else {
            logger.warn("设置的日志处理器未继承:{},采用默认处理器:", asyncLogProperties.getLogProcessor(), BusinessLogProcessor.class.getName());
            return new BusinessLogProcessor();
        }
    }

    /**
     * 
     *
     * @throws Exception 
     * @see org.springframework.beans.factory.DisposableBean#destroy()
     */
    @Override
    public void destroy() throws Exception {
        logger.info("开始销毁异步线程池");
        if (threadPoolExecutor != null) {
            try {
                threadPoolExecutor.shutdown();
                //观察30秒是否成功关闭线程池，否则调用shutdownNow再次关闭;
                if (!threadPoolExecutor.awaitTermination(30,  TimeUnit.SECONDS)) {
                    threadPoolExecutor.shutdownNow();
                }
            } catch (Exception ex) {
                logger.error("异步线程池关闭异常, msg:{}", ex.getMessage());
                ex.printStackTrace();
            }
        }
        logger.info("成功销毁异步线程池");
    }
}